#pragma once

#include "iterator.h"

namespace sfc::iter {

template <class F, class... Args>
using invoke_result_t = decltype(declval<F>()(declval<Args>()...));

template <class I, class F>
struct Map {
  using Item = decltype(declval<F>()(declval<typename I::Item>()));

  I _iter;
  F _func;

 public:
  [[sfc_inline]] auto len() const -> usize {
    return _iter.len();
  }

  [[sfc_inline]] auto next() -> option::Option<Item> {
    auto val = _iter.next();
    if (!val) return {};
    return _func(mem::move(val).unwrap());
  }

  [[sfc_inline]] auto next_back() -> option::Option<Item> {
    auto val = _iter.next_back();
    if (!val) return {};
    return _func(mem::move(val).unwrap());
  }
};

template <class I>
template <class F>
auto Iter<I>::map(F func) {
  return Map<I, F>{static_cast<I&&>(*this), static_cast<F&&>(func)};
}

}  // namespace sfc::iter
